unit uHashTable;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, IniFiles;

type
  PPHashItem = ^PHashItem;
  PHashItem = ^THashItem;
  THashItem = record
    Next: PHashItem;  
    Key: String;  
    Value: Variant;  
  end;

  THashTable = class  
  private  
    Buckets: array of PHashItem;  
  protected  
    function Find(const Key: String): PPHashItem;  
    function HashOf(const Key: String): Cardinal; virtual;  
  public  
    constructor Create(Size: Cardinal = 256);  
    destructor Destroy; override;  
    procedure Put(const Key: String; Value: Variant);  
    procedure Clear;  
    procedure Remove(const Key: String);  
    function Modify(const Key: String; Value: Variant): Boolean;  
    function Get(const Key: String): Variant;  
    function ContainKey(const Key: String):boolean;  
  end;

implementation

procedure THashTable.Clear;  
var  
  I: Integer;  
  P, N: PHashItem;  
begin  
  for I := 0 to Length(Buckets) - 1 do  
  begin  
    P := Buckets[I];  
    while P <> nil do  
    begin  
      N := P^.Next;  
      Dispose(P);  
      P := N;  
    end;  
    Buckets[I] := nil;  
  end;  
end;  
function THashTable.ContainKey(const Key: String): boolean;  
var  
  P: PHashItem;  
begin  
  P := Find(Key)^;  
  if P <> nil then  
  begin  
    Result := True;  
  end  
  else  
    Result := False;  
end;  
constructor THashTable.Create(Size: Cardinal);  
begin  
  inherited Create;  
  SetLength(Buckets, Size);  
end;  
destructor THashTable.Destroy;  
begin  
  Clear;  
  inherited Destroy;  
end;  
function THashTable.Find(const Key: String): PPHashItem;  
var  
  Hash: Integer;  
begin  
  Hash := HashOf(Key) mod Cardinal(Length(Buckets));  
  Result := @Buckets[Hash];  
  while Result^ <> nil do  
  begin  
    if Result^.Key = Key then  
      Exit  
    else  
      Result := @Result^.Next;  
  end;  
end;  
function THashTable.Get(const Key: String): Variant;  
var  
  P: PHashItem;  
begin  
  P := Find(AnsiUpperCase(Key))^;  
  if P <> nil then  
    Result := P^.Value  
  else  
    Result := -1;  
end;  
function THashTable.HashOf(const Key: String): Cardinal;  
var  
  I: Integer;  
begin  
  Result := 0;  
  for I := 1 to Length(Key) do  
    Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor  
      Ord(Key[I]);  
end;  
function THashTable.Modify(const Key: String; Value: Variant): Boolean;  
var  
  P: PHashItem;  
begin  
  P := Find(Key)^;  
  if P <> nil then  
  begin  
    Result := True;  
    P^.Value := Value;  
  end  
  else  
    Result := False;  
end;  
procedure THashTable.Put(const Key: String; Value: Variant);  
var  
  Hash: Integer;  
  Bucket: PHashItem;  
begin  
  Hash := HashOf(AnsiUpperCase(Key)) mod Cardinal(Length(Buckets));  
  New(Bucket);  
  Bucket^.Key := AnsiUpperCase(Key);  
  Bucket^.Value := Value;  
  Bucket^.Next := Buckets[Hash];  
  Buckets[Hash] := Bucket;  
end;  
procedure THashTable.Remove(const Key: String);  
var  
  P: PHashItem;  
  Prev: PPHashItem;  
begin  
  Prev := Find(Key);  
  P := Prev^;  
  if P <> nil then  
  begin  
    Prev^ := P^.Next;  
    Dispose(P);  
  end;  
end;
end.
 